// Copyright (C) 2008 Victor Marzo
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library.  Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
// 
// As a special exception, the copyright holders of this library give you
// permission to link this library with independent modules to produce an
// executable, regardless of the license terms of these independent
// modules, and to copy and distribute the resulting executable under
// terms of your choice, provided that you also meet, for each linked
// independent module, the terms and conditions of the license of that
// module.  An independent module is a module which is not derived from
// or based on this library.  If you modify this library, you may extend
// this exception to your version of the library, but you are not
// obligated to do so.  If you do not wish to do so, delete this
// exception statement from your version.

using System;
using System.Reflection;
using System.Collections.Generic;

namespace NForth
{
	public class Dictionary
	{
        private static List<string> namespaces = new List<string>();
        private static Word latest = null;
		
		public static Word Latest
		{
			get { return latest; }
		}
		
		public static void Create(string name)
		{
			latest = new Word(name, latest);
		}
		
		public static void Create(string name, MethodInfo method_info)
		{
			latest = new Word(name, method_info, latest);
		}

        public static void ClearNamespaces()
        {
            namespaces.Clear();
            namespaces.Add("");
        }

        public static void AddNamespace(string n)
        {
            namespaces.Add(n + ".");
        }
		
		public static Word FindWord(string name)
		{

			Word w = latest;
			while(w != null && (w.Name != name || w.Hidden != 0))
				w = w.Previous;
			return w;
		}

        public static MethodInfo FindMethod(string word_name)
        {
            Word word = Dictionary.FindWord(word_name);
            if (word != null)
                return word.Method;

            int index = word_name.LastIndexOf('.');
            if (index < 0)
                return null;

            string name = word_name.Substring(0, index);
            Type type = FindType(name);
            if (type == null)
                return null;

            string method = word_name.Substring(index + 1);
            string[] args = method.Split('`');

            Type[] types = new Type[args.Length - 1];
            for (int i = 0; i < types.Length; i++)
                types[i] = FindType(args[i + 1]);

            MethodInfo method_info = type.GetMethod(args[0], types);
            if (method_info == null)
                method_info = type.GetMethod(args[0]);

            return method_info;
        }

        public static FieldInfo FindField(string word_name)
        {
            int index = word_name.LastIndexOf('.');
            if (index < 0)
                return null;

            string name = word_name.Substring(0, index);
            Type type = FindType(name);
            if (type == null)
                return null;

            string field = word_name.Substring(index + 1);
            FieldInfo field_info = type.GetField(field);

            return field_info;
        }

        public static Type FindType(string type_name)
        {
            foreach (string ns in namespaces)
            {
                Type type = Type.GetType(ns + type_name, false, true);
                if (type != null)
                    return type;
            }

            return null;
        }
    }
}
